package com.github.cosycode.imgtool.util;

import com.github.cosycode.common.lang.ShouldNotHappenException;
import com.github.cosycode.common.util.io.FileSystemUtils;
import com.github.cosycode.common.util.io.StreamUtils;
import com.google.common.net.UrlEscapers;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.function.LongBinaryOperator;

/**
 * <b>Description : </b>
 * <p>
 * <b>created in </b> 2021/4/19
 *
 * @author CPF
 * @since 1.0
 **/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Slf4j
public class HttpUtils {


    /**
     * CURL 发送请求, 获取响应字符串
     *
     * @param url 请求路径
     * @return 响应字符串
     */
    public static String sendGetRequest(String url) {
        HttpGet httpGet = new HttpGet(url);
        String result = null;
        int status = 0;
        try (CloseableHttpClient httpClient = HttpClientBuilder.create().build(); CloseableHttpResponse response = httpClient.execute(httpGet)) {
            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();
            // 响应状态
            status = response.getStatusLine().getStatusCode();
            if (status == 200) {
                // 响应结果, 默认 UTF-8 解码编码
                result = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
            }
            return result;
        } catch (ClientProtocolException e) {
            log.warn("客户端请求失败", e);
        } catch (IOException e) {
            log.warn("IO exception!", e);
        }
        return result;
    }

    /**
     * @param url                url
     * @param savePath           存储路径
     * @param longBinaryOperator 回调函数, 用于获取下载进度
     * @return 是否下载成功
     */
    public static boolean download(String url, File savePath, LongBinaryOperator longBinaryOperator) {
        Objects.requireNonNull(savePath);
        CloseableHttpClient client = HttpClients.custom()
                .setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build())
                .build();
        // cookie时间可能会出错，设置下
        try {
            // 防止url 里面有特殊字符导致 请求失败, 该函数会将  https://shu.io/upload|im 转变成 https://shu.io/upload%7Cim
            String encodeUrl = UrlEscapers.urlFragmentEscaper().escape(url);
            HttpGet httpget = new HttpGet(encodeUrl);
            HttpResponse response = client.execute(httpget);
            HttpEntity entity = response.getEntity();
            // 文件大小
            final long contentLength = entity.getContentLength();
            if (!savePath.exists()) {
                FileSystemUtils.insureFileDirExist(savePath.getParentFile());
            }
            try (InputStream is = entity.getContent(); OutputStream outputStream = new FileOutputStream(savePath)) {
                StreamUtils.streamTransfer(is, outputStream, p -> {
                    if (longBinaryOperator != null) {
                        longBinaryOperator.applyAsLong(contentLength, p);
                    }
                });
            } catch (FileNotFoundException e) {
                throw new ShouldNotHappenException(e);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 仅仅判断资源路径下的文件是否存在
     *
     * @param urlPath url 资源路径
     */
    public static boolean isUrlResExist(String urlPath) {
        try {
            URL url = new URL(urlPath);
            // 返回一个 URLConnection 对象，它表示到 URL 所引用的远程对象的连接。
            URLConnection uc = url.openConnection();
            // 打开的连接读取的输入流。
            try (InputStream in = uc.getInputStream()) {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
    }


}
